home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 43 / Amiga Format CD43 (1999)(Future Publishing)(GB)(Track 1 of 2)[!][issue 1999-09].iso / -serious- / wb / flynn / source / subtask.c < prev    next >
C/C++ Source or Header  |  1999-06-15  |  11KB  |  510 lines

  1. /*****************************************************************
  2. ------------------------------------------------------------------
  3.  
  4.     subtask administration
  5.     
  6. ------------------------------------------------------------------
  7. *****************************************************************/
  8.  
  9. #define MAGICNUMBER        0x0CBF0CBF
  10.  
  11. #include <assert.h>
  12.  
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include <stdlib.h>
  16.  
  17. #include <exec/tasks.h>
  18. #include <exec/semaphores.h>
  19. #include <dos/dostags.h>
  20. #include <dos/dosextens.h>
  21.  
  22. #include <proto/exec.h>
  23. #include <proto/dos.h>
  24. #include <proto/utility.h>
  25. #include <clib/alib_protos.h>
  26.  
  27. #include "subtask.h"
  28. #include "debug.h"
  29.  
  30. struct subtask
  31. {
  32.     struct Message msg;
  33.  
  34.     ULONG ID;                    /* identifier with magic number */
  35.  
  36.     WORD prio;
  37.  
  38.     struct Task *parenttask;    /* Parent Task that launched subtask */
  39.     struct Process *subproc;    /* the subtask */
  40.  
  41.     BYTE signal_abort;            /* signals subtask to abort */
  42.     BYTE signal_go;                /* signals parent task when started */
  43.     BYTE signal_ready;            /* signals parent task when ready */
  44.     UBYTE pad;
  45.  
  46.     LONG (* function) (APTR, BYTE);                /* sub task function */
  47.     LONG result;                                /* result from function */
  48.  
  49.     struct SignalSemaphore datasemaphore;        /* shared data protection */
  50.     APTR data;                                    /* any kind of data */
  51.  
  52.     BOOL running;
  53.     
  54.     BOOL (* initfunction) (APTR);                /* init function */
  55.  
  56.     BOOL selfdestruct;            /* subtask closes down automatically */
  57.     
  58.     char procname[100];
  59. };
  60.  
  61.  
  62.  
  63. /*********************************************************************
  64. ----------------------------------------------------------------------
  65.  
  66.     SubTaskEntry
  67.  
  68. ----------------------------------------------------------------------
  69. *********************************************************************/
  70.  
  71. void __saveds SubTaskEntry(void)
  72. {
  73.     struct Task *mytask;
  74.     struct subtask *subtask = NULL;
  75.     char *myname;
  76.     struct MsgPort *myport;
  77.     BOOL success = TRUE;
  78.  
  79.  
  80.     /*    find own name - it will be the same as for the message port */
  81.  
  82.     mytask = FindTask(NULL);
  83.     myname = mytask->tc_Node.ln_Name;
  84.  
  85.  
  86.     if (!(myport = CreatePort(myname, 1)))
  87.     {
  88.         DB(kprintf("*** Subtask %s Error: could not create message port.\n", myname));
  89.         success = FALSE;
  90.     }
  91.  
  92.  
  93.     /*    wait for parent's message to arrive at the msgport */
  94.  
  95.     if (success)
  96.     {    
  97.         subtask = (struct subtask *) WaitPort(myport);
  98.  
  99.         if (subtask->ID != MAGICNUMBER)
  100.         {
  101.             DB(kprintf("*** Subtask %s Error: handshaking error.\n", myname));
  102.             success = FALSE;
  103.         }
  104.     }
  105.         
  106.     if ((subtask->signal_abort = AllocSignal(-1)) == -1)
  107.     {
  108.         DB(kprintf("*** Subtask %s Error: no signal.\n", myname));
  109.         success = FALSE;
  110.     }
  111.  
  112.  
  113.     if (success)
  114.     {
  115.         if (subtask->initfunction)
  116.         {
  117.             success = subtask->initfunction((APTR) subtask->data);
  118.             
  119.             if (!success)
  120.             {
  121.                 subtask->running = TRUE;
  122.                 Signal(subtask->parenttask, 1 << subtask->signal_go);
  123.             }
  124.         }
  125.  
  126.         if (success)
  127.         {
  128.             Forbid();
  129.  
  130.             /*    signal parent task that we're running */
  131.         
  132.             Signal(subtask->parenttask, 1 << subtask->signal_go);
  133.             subtask->running = TRUE;
  134.     
  135.             /*    call function */
  136.  
  137.             if (!(SetSignal(0,0) & (1 << subtask->signal_abort)))
  138.             {
  139.                 /*    now set our priority */
  140.  
  141.                 SetTaskPri(mytask, subtask->prio);
  142.  
  143.                 Permit();
  144.                 DB(kprintf("calling subtask function\n"));
  145.                 
  146.                 /*    call function */
  147.                 
  148.                 subtask->result = subtask->function((APTR)subtask, subtask->signal_abort);
  149.             }
  150.             else
  151.             {
  152.                 Permit();
  153.             }
  154.         }
  155.     }
  156.  
  157.  
  158.     /*    close down in forbid status completely */
  159.  
  160.     Forbid();
  161.  
  162.     /*    signal parent task that we're ready */
  163.  
  164.     subtask->running = FALSE;
  165.  
  166.     if (subtask)
  167.     {
  168.         if (!subtask->selfdestruct)
  169.         {
  170.             Signal(subtask->parenttask, 1 << subtask->signal_ready);
  171.         //    ReplyMsg((struct Message *) subtask);
  172.             FreeSignal(subtask->signal_abort);
  173.         }
  174.         else
  175.         {
  176.             DB(kprintf("§§§ selfdestruct task closing down\n"));
  177.             FreeSignal(subtask->signal_abort);
  178.             free(subtask);
  179.         }
  180.     }
  181.  
  182.     if (myport)
  183.     {
  184.         DeletePort(myport);
  185.     }
  186.  
  187. }
  188.  
  189.  
  190. /*********************************************************************
  191. ----------------------------------------------------------------------
  192.  
  193.     subtask = SubTask(function, data, stacksize, prio, name, initfunc, selfdestruct)
  194.  
  195. ----------------------------------------------------------------------
  196. *********************************************************************/
  197.  
  198. APTR SubTask(LONG (* function)(struct subtask *, BYTE), 
  199.     APTR data, ULONG stacksize, WORD prio, char *name,
  200.     BOOL (* initfunction)(struct subtask *),
  201.     BOOL selfdestruct)
  202. {
  203.     struct subtask *st;
  204.     BOOL success = FALSE;
  205.  
  206.     if (st = malloc(sizeof(struct subtask)))
  207.     {
  208.         memset(st, 0, sizeof(struct subtask));
  209.  
  210.         st->parenttask = FindTask(NULL);
  211.         st->signal_ready = -1;
  212.         st->signal_go = -1;
  213.  
  214.         if (selfdestruct)
  215.         {
  216.             success = TRUE;
  217.         }
  218.         else
  219.         {
  220.             if ((st->signal_ready = AllocSignal(-1)) >= 0)
  221.             {
  222.                 success = TRUE;
  223.             }
  224.         }
  225.  
  226.         if (success)
  227.         {
  228.             success = FALSE;
  229.         
  230.             if ((st->signal_go = AllocSignal(-1)) >= 0)
  231.             {
  232.                 InitSemaphore(&st->datasemaphore);
  233.                 st->ID = MAGICNUMBER;
  234.                 st->function = function;
  235.                 st->initfunction = initfunction;
  236.                 st->data = data;
  237.                 st->prio = prio;
  238.                 st->running = TRUE;    //FALSE;
  239.                 st->msg.mn_Length = sizeof(struct subtask);
  240.                 st->selfdestruct = selfdestruct;
  241.  
  242.                 sprintf(st->procname, name, GetUniqueID());
  243.  
  244.                 if (st->subproc = CreateNewProcTags(NP_Entry, (ULONG) SubTaskEntry,
  245.                     NP_StackSize, stacksize,
  246.                     NP_Name, (ULONG) st->procname, TAG_DONE))
  247.                 {
  248.                     struct MsgPort *port = NULL;
  249.  
  250.                     while (!port)
  251.                     {
  252.                         Forbid();
  253.                         port = FindPort(st->procname);
  254.                         Permit();
  255.                         if (!port)
  256.                         {
  257.                             Delay(1);
  258.                         }
  259.                     }
  260.                 
  261.                     PutMsg(port, (struct Message *) st);
  262.  
  263.                     Wait(1 << st->signal_go);
  264.  
  265.                     success = TRUE;
  266.  
  267.                 }
  268.                 FreeSignal(st->signal_go);
  269.             }
  270.         }
  271.     }
  272.  
  273.     
  274.     if (!success)
  275.     {
  276.         if (st)
  277.         {
  278.             FreeSignal(st->signal_ready);
  279.             free(st);
  280.             st = NULL;
  281.         }
  282.     }
  283.  
  284.     return (APTR) st;
  285. }
  286.  
  287.  
  288. /*********************************************************************
  289. ----------------------------------------------------------------------
  290.  
  291.     UBYTE SubTaskReadySignal(subtask)
  292.  
  293. ----------------------------------------------------------------------
  294. *********************************************************************/
  295.  
  296. BYTE SubTaskReadySignal(APTR subtask)
  297. {
  298.     return ((struct subtask *) subtask)->signal_ready;
  299. }
  300.  
  301.  
  302. /*********************************************************************
  303. ----------------------------------------------------------------------
  304.  
  305.     AbortSubTask(subtask)
  306.     
  307.     when this function returns, it must not be assumed
  308.     that the subtask actually aborted. you must still
  309.     WaitSubTaks() or CloseSubTask() thereafter.
  310.  
  311. ----------------------------------------------------------------------
  312. *********************************************************************/
  313.  
  314. void AbortSubTask(APTR subtask)
  315. {
  316.     if (subtask)
  317.     {
  318.         struct subtask *st = (struct subtask *) subtask;
  319.  
  320.         DB(kprintf("§ aborting subtask %s:%lx\n", st->procname, subtask));
  321.  
  322.         Forbid();
  323.         if (st->running)
  324.         {
  325.             Signal(&st->subproc->pr_Task, 1 << st->signal_abort);
  326.         }
  327.         else
  328.         {
  329.             DB(kprintf("*** subtask was not running!!!\n"));
  330.         }
  331.         Permit();
  332.     }
  333. }
  334.  
  335.  
  336.  
  337. /*********************************************************************
  338. ----------------------------------------------------------------------
  339.  
  340.     ready = SubTaskReady(subtask)
  341.  
  342. ----------------------------------------------------------------------
  343. *********************************************************************/
  344.  
  345. BOOL SubTaskReady(APTR subtask)
  346. {
  347.     if (subtask)
  348.     {
  349.         struct subtask *st = (struct subtask *) subtask;
  350.         ULONG mask = 1 << st->signal_ready;
  351.         return (BOOL) !!(SetSignal(0, 0) & mask);
  352.     }
  353. }
  354.  
  355.  
  356. /*********************************************************************
  357. ----------------------------------------------------------------------
  358.  
  359.     result = WaitSubTask(subtask)
  360.  
  361. ----------------------------------------------------------------------
  362. *********************************************************************/
  363.  
  364. LONG WaitSubTask(APTR subtask)
  365. {
  366.     if (subtask)
  367.     {
  368.         struct subtask *st = (struct subtask *) subtask;
  369.  
  370.         DB(kprintf("§ waiting for subtask %s:%lx\n", st->procname, subtask));
  371.  
  372.         if (st->running)
  373.         {
  374.             Wait(1 << st->signal_ready);
  375.         }
  376.         else
  377.         {
  378.             DB(kprintf("*** subtask was not running!!!\n"));
  379.         }
  380.  
  381.         return st->result;
  382.     }
  383.     
  384.     return NULL;
  385. }
  386.  
  387.  
  388. /*********************************************************************
  389. ----------------------------------------------------------------------
  390.  
  391.     CloseSubTask(subtask)
  392.  
  393. ----------------------------------------------------------------------
  394. *********************************************************************/
  395.  
  396. LONG CloseSubTask(APTR subtask)
  397. {
  398.     if (subtask)
  399.     {
  400.         LONG result;
  401.         struct subtask *st = (struct subtask *) subtask;
  402.  
  403.         DB(kprintf("§ waiting for subtask %s:%lx to close down\n", st->procname, subtask));
  404.     
  405.         result = WaitSubTask(subtask);
  406.         
  407.         SetSignal(0, 1 << st->signal_ready);
  408.     
  409.         FreeSignal(st->signal_ready);
  410.         free(subtask);
  411.         
  412.         return result;
  413.     }
  414.  
  415.     return NULL;
  416. }
  417.  
  418.  
  419.  
  420. /*********************************************************************
  421. ----------------------------------------------------------------------
  422.  
  423.     ObtainData(subtask)
  424.  
  425. ----------------------------------------------------------------------
  426. *********************************************************************/
  427.  
  428. APTR ObtainData(APTR subtask)
  429. {
  430.     struct subtask *st = (struct subtask *) subtask;
  431.  
  432.     ObtainSemaphore(&st->datasemaphore);
  433.     
  434.     return st->data;
  435. }
  436.  
  437.  
  438. /*********************************************************************
  439. ----------------------------------------------------------------------
  440.  
  441.     ObtainDataShared(subtask)
  442.  
  443. ----------------------------------------------------------------------
  444. *********************************************************************/
  445.  
  446. APTR ObtainDataShared(APTR subtask)
  447. {
  448.     struct subtask *st = (struct subtask *) subtask;
  449.  
  450.     ObtainSemaphoreShared(&st->datasemaphore);
  451.  
  452.     return st->data;
  453. }
  454.  
  455.  
  456. /*********************************************************************
  457. ----------------------------------------------------------------------
  458.  
  459.     ReleaseData(subtask)
  460.  
  461. ----------------------------------------------------------------------
  462. *********************************************************************/
  463.  
  464. void ReleaseData(APTR subtask)
  465. {
  466.     struct subtask *st = (struct subtask *) subtask;
  467.  
  468.     ReleaseSemaphore(&st->datasemaphore);
  469. }
  470.  
  471.  
  472.  
  473. /*********************************************************************
  474. ----------------------------------------------------------------------
  475.  
  476.     SignalSubTask(subtask, signals)
  477.  
  478. ----------------------------------------------------------------------
  479. *********************************************************************/
  480.  
  481. void SignalSubTask(APTR subtask, ULONG signals)
  482. {
  483.     if (subtask)
  484.     {
  485.         struct subtask *st = (struct subtask *) subtask;
  486.  
  487.         DB(kprintf("§ signalling subtask %s:%lx\n", st->procname, subtask));
  488.  
  489.         Signal(&st->subproc->pr_Task, signals);
  490.     }
  491. }
  492.  
  493.  
  494. /*********************************************************************
  495. ----------------------------------------------------------------------
  496.  
  497.     SignalParentTask(subtask, signals)
  498.  
  499. ----------------------------------------------------------------------
  500. *********************************************************************/
  501.  
  502. void SignalParentTask(APTR subtask, ULONG signals)
  503. {
  504.     if (subtask)
  505.     {
  506.         struct subtask *st = (struct subtask *) subtask;
  507.         Signal(st->parenttask, signals);
  508.     }
  509. }
  510.